#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@NAME          : ini_app.py
@TIME          : 2024/11/12 18:55:16
@AUTHOR        : chenlip
@VERSION       : 0.0.1
@DESCRIPTION   : 用于初始化flask app
'''
# --------------------------引用--------------------------
import socket
import hashlib

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import create_engine
from flask_cors import CORS
# from flask_socketio import SocketIO
from flask_caching import Cache
from flask_login import LoginManager
from flask_jwt_extended import JWTManager
from flask_wtf.csrf import CSRFProtect, generate_csrf

# 统一日志记录器
from app.common.logutil import init_app_logger

from app.conf.config import conf

# 自定义的jinja2模板
from app.middlewares.jinja2template import init_template_functions

from app.common.minioact import minioclient

# 引入蓝图初始化函数
from app.blueprints import init_all_blueprints

# rust api
# from app.bluepoints.api.fileapi import fileapi
# from app.bluepoints.api import api_bp

# 自定义的中间件，用于记录请求日志，或其他自定义请求前后的处理
from app.middlewares.request_logger import init_request_logger
# 自定义错误处理中间件
from app.middlewares.error_handler import init_error_handler

# 初始化扩展
sqldb = SQLAlchemy()  # 全局数据库实例
# socketio = SocketIO()  # SocketIO实例
login_manager = LoginManager()  # 登录管理实例
jwt_manager = JWTManager()  # JWT管理

cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})  # 缓存实例

# 获取机器ID
def get_machine_id():
    """
    基于主机名和IP地址生成0-5范围内的机器ID
    """
    # 获取主机名
    hostname = socket.gethostname()
    
    # 获取IP地址
    try:
        ip = socket.gethostbyname(hostname)
    except:
        ip = '127.0.0.1'
    
    # 组合主机标识
    machine_str = f"{hostname}:{ip}"
    
    # 使用哈希函数计算0-31之间的值
    hash_value = int(hashlib.md5(machine_str.encode()).hexdigest(), 16)
    return hash_value % 6  # 限制在0-5范围内

# 初始化数据库
def init_db(app: Flask):    
    # 初始化SQLAlchemy

    sqldb.init_app(app)

def init_app_routes(app: Flask):
    """
    在应用初始化时保存路由表信息，供其他应用使用
    """
    # 收集路由信息
    route_info = []
    for rule in app.url_map.iter_rules():
        route_info.append({
            'endpoint': rule.endpoint,
            'methods': sorted(list(rule.methods)),
            'path': str(rule),
            'arguments': list(rule.arguments)
        })

    # 保存到应用配置
    app.config['ROUTE_INFO'] = route_info

# 初始化中间件
def init_middlewares(app: Flask):
    # 初始化请求日志中间件
    init_request_logger(app)
    # 初始化错误处理中间件
    init_error_handler(app)

# 初始化扩展
def init_extensions(app: Flask):

    # 初始化SocketIO
    # socketio.init_app(app)
    # 从app.config中读取配置
    dconf = app.config['CORSSITES']

    # 初始化跨域保护，只允许指定的站点访问，防止CSRF攻击，需要安装flask-cors
    CORS(app, resources={r"/*": {"origins": dconf}})

    # 初始化登录管理
    login_manager.init_app(app)

    # 设置登录视图
    login_manager.login_view = 'user.login'      # 指定登录页面路由
    login_manager.login_message = 'login_manager:请先登录才能访问此页面'  # 登录提示消息
    login_manager.login_message_category = 'info'  # 消息类别，用于flash消息样式
    
    @login_manager.user_loader
    def load_user(user_id):
        try:
            from app.models.user import User
            user = User.query.get(int(user_id))
            return user
        except Exception as e:
            print(f"加载用户出错: {str(e)}")
            return None
        return user

    # 初始化JWT管理, 相关配置已经放在config.py中
    jwt_manager.init_app(app)

    # 初始化缓存
    cache.init_app(app)

    # 初始化CSRF保护 - 统一处理CSRF保护
    csrf = CSRFProtect(app)
    
    # 确保CSRF令牌在所有模板中可用
    @app.context_processor
    def inject_csrf_token():
        return {'csrf_token': generate_csrf()}
    
    # 注册应用关闭时的回调函数，用于关闭通知服务线程
    @app.teardown_appcontext
    def shutdown_notification_service(exception=None):
        from app.service.sse_notifi import NotificationService
        NotificationService.shutdown()

    # 其他扩展的初始化可以在这里添加

# 初始化蓝图
def init_blueprints(app: Flask):

    # 注册系统管理模块蓝图
    init_all_blueprints(app)

    # 注册API蓝图
    
    # app.register_blueprint(api_bp) # 注册API蓝图
    # app.register_blueprint(fileapi) # 注册文件操作restful API


def create_app(config_env: str = 'dev') -> Flask:
    app = Flask(__name__)
    app.config.from_object(conf[config_env])

    app.config['is_prod'] = config_env == 'prod' # 是否生产环境

    app.config['MINIO'] = minioclient()
    app.config['MINIO2'] = minioclient(bucket_name='mdblog')
    # 生成机器ID
    app.config['MACHINE_ID'] = get_machine_id()

    # 设置静态目录
    app.static_folder = 'static'
    # 设置模板目录
    app.template_folder = 'templates'

    # 初始化日志管理器
    init_app_logger(app)
    
    # 初始化数据库
    init_db(app)

    # 保存路由表信息
    init_app_routes(app)

    # 初始化中间件
    init_middlewares(app)

    # 加载其他扩展和模块
    # 例如：登录验证模块、跨域保护模块、SocketIO模块等
    init_extensions(app)

    # 初始化自定义Jinja2模板函数
    init_template_functions(app)

    # 注册蓝图,包括API蓝图
    init_blueprints(app)


    return app



